/*
 * Copyright 2013 meichenhui
 * 
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 * 
 * http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */
package com.googlecode.zet.tool.pluginanalyzer;

import java.io.Console;
import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Set;

import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import org.eclipse.osgi.service.resolver.BundleDescription;
import org.eclipse.osgi.service.resolver.BundleSpecification;

/**
 * @author meichenhui
 * 
 */
public class CommandAN implements Command {

    protected static final String ERROR_ONE_OR_MORE_WHITESPACE = "Error more then one whitespace found!";

    protected static final String PATH_SPARATOR                = ";,";

    protected static final String ERROR_INVALID_PATH           = "Invalid file path [%1$s]%n";

    protected static final String MISSING_PLUGINS              = "Missing plugins :%n%1$s%n";

    @Override
    public void exec(Console console, String params) {
        // FIXME:参数个数输入不正确时没有处理.比如少输入一个路径
        ANArguments arguments = parseArguments(params);
        DependencyAnalyzer analyzer = new DependencyAnalyzer();
        List<SimpleBundleDescription> runtimeDescriptions = analyzePluginDesciptions(
                console, arguments.getRuntimePaths(), analyzer);
        List<SimpleBundleDescription> pluginDescriptions = analyzePluginDesciptions(
                console, arguments.getPluginPaths(), analyzer);
        Set<BundleSpecification> missingPlugins = analyzer
                .computeMissingPlugins(runtimeDescriptions
                        .toArray(new SimpleBundleDescription[0]),
                        pluginDescriptions
                                .toArray(new SimpleBundleDescription[0]));

        console.printf(MISSING_PLUGINS, formatOutputMissingBundles(missingPlugins));
    }

    protected String formatOutputMissingBundles(
            Set<BundleSpecification> missingBundles) {
        List<BundleSpecification> sorted = sortMissingBundles(missingBundles);
        StringBuilder output = new StringBuilder();
        for (BundleSpecification aDescription : sorted) {
            output.append(aDescription);
            output.append("\n");
        }
        return output.length() > 0 ? output.substring(0,output.length()) : StringUtils.EMPTY;
    }
    
    protected List<BundleSpecification> sortMissingBundles(Set<BundleSpecification> missingBundles){
        List<BundleSpecification> sorted = new ArrayList<BundleSpecification>(missingBundles);
        Collections.sort(sorted, new Comparator<BundleSpecification>() {

            @Override
            public int compare(BundleSpecification right, BundleSpecification left) {
                return right.getName().compareTo(left.getName());
            }
        });
        return sorted;
    }

    protected List<SimpleBundleDescription> analyzePluginDesciptions(
            final Console console, List<String> pluginPaths, DependencyAnalyzer analyzer) {
        List<SimpleBundleDescription> runtimeDescriptions = new ArrayList<SimpleBundleDescription>();
        for (String aRuntimePath : pluginPaths) {
            File runtimeFile = new File(aRuntimePath);
            if (runtimeFile.isDirectory()) {
                try {
                    runtimeDescriptions.addAll(analyzer
                            .createBundlesDescription(aRuntimePath,new ExceptionHandler() {
                                
                                @Override
                                public void handle(Exception e) {
                                    if (!CommandVerbose.verbose){
                                        return;
                                    }
                                    console.printf("%1$s%n", e);
                                }
                            }));
                } catch (DirectoryNotFoundException e) {
                    console.printf("%1$s%n", e);
                }
                continue;
            }
            if (runtimeFile.isFile()) {
                try {
                    runtimeDescriptions.add(analyzer
                            .createBundleDescription(aRuntimePath));
                } catch (ManifestNotFoundException e){
                    console.printf("%1$s%n",e);
                }
                continue;
            }
            console.printf(ERROR_INVALID_PATH, aRuntimePath);
        }
        return runtimeDescriptions;
    }

    @Override
    public ANArguments parseArguments(String params) {
        String[] runtimeAndPlugin = splitRuntimeAndPlugin(params);
        ANArguments anArguments = new ANArguments();
        // runtime paths
        String[] runtimePaths = StringUtils.split(runtimeAndPlugin[0],
                PATH_SPARATOR);
        anArguments.setRuntimePaths(Arrays.asList(runtimePaths));
        if (runtimeAndPlugin.length < 2) {
            return anArguments;
        }
        // plugin paths
        String[] pluginPaths = StringUtils.split(runtimeAndPlugin[1],
                PATH_SPARATOR);
        anArguments.setPluginPaths(Arrays.asList(pluginPaths));
        return anArguments;
    }

    /**
     * 解析路径参数<br/>
     * 不支持带空格的路径,会抛出{@line RuntimeException}.
     * 
     * @param params
     * @return
     * 
     */
    protected String[] splitRuntimeAndPlugin(String params) {
        // FIXME 只是简单的使用空格作为分隔符,对场景的支持还不完整.
        // 例如:1.带空格的目录名称;2.重复的路径;3.windows/unix路径表示.等等
        if (params == null || StringUtils.isEmpty(params)) {
            return new String[0];
        }
        if (StringUtils.countMatches(params, " ") > 1) {
            throw new RuntimeException(ERROR_ONE_OR_MORE_WHITESPACE);
        }
        return params.split(" ");
    }

    public class ANArguments {
        private List<String> runtimePaths = new ArrayList<String>();

        private List<String> pluginPaths  = new ArrayList<String>();

        public List<String> getRuntimePaths() {
            return runtimePaths;
        }

        public void setRuntimePaths(List<String> runtimePaths) {
            this.runtimePaths = runtimePaths;
        }

        public List<String> getPluginPaths() {
            return pluginPaths;
        }

        public void setPluginPaths(List<String> pluginPaths) {
            this.pluginPaths = pluginPaths;
        }

    }
}
